package top.heue.utils.lifecycle.helper

import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import top.heue.utils.log.L
import kotlin.coroutines.CoroutineContext

object CoroutineHelper {
    var handler: CoroutineHandler = { coroutineContext, throwable ->
        L.e("CoroutineHelper: $coroutineContext", throwable)
    }
        private set

    /**
     * Error Handler
     * @param handler 函数体
     */
    fun setDefaultHandler(handler: CoroutineHandler) {
        this.handler = handler
    }


    fun execution(
        context: CoroutineContext,
        block: CoroutineBlock,
        handler: CoroutineHandler,
        start: CoroutineStart
    ): Job = run {
        val errorHandler = CoroutineExceptionHandler(handler)
        CoroutineScope(context).launch(errorHandler, start = start, block = block)
    }
}

fun onIo(
    handler: CoroutineHandler = CoroutineHelper.handler,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: CoroutineBlock
) = CoroutineHelper.execution(Dispatchers.IO, block, handler, start)

fun onMain(
    handler: CoroutineHandler = CoroutineHelper.handler,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: CoroutineBlock
) = CoroutineHelper.execution(Dispatchers.Main, block, handler, start)

fun onDefault(
    handler: CoroutineHandler = CoroutineHelper.handler,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: CoroutineBlock
) = CoroutineHelper.execution(Dispatchers.Default, block, handler, start)

fun onUnconfined(
    handler: CoroutineHandler = CoroutineHelper.handler,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: CoroutineBlock,
) = CoroutineHelper.execution(Dispatchers.Unconfined, block, handler, start)


typealias CoroutineBlock = suspend CoroutineScope.() -> Unit
typealias CoroutineHandler = (context: CoroutineContext, throwable: Throwable) -> Unit